﻿/* 
 * Evo
 * 
 * Marcin Krupowicz (marcin@krupowicz.eu)
 * Barbara Szymanek (basia.szymanek@gmail.com)
 * 
 * January, 2009
 *
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace Evo.Operators
{
	/// <summary>
	/// Kills some percentage of population and replace it by new, random individuals
	/// </summary>
	/// <typeparam name="T">Type of individuals of population</typeparam>
	public class DisasterOperator<T> : IOperator<T> where T : IIndividual
	{
		protected double probability;
		protected double fraction;
		protected static Random random = new Random(DateTime.Now.Millisecond);

		/// <summary>
		/// Create DisasterOperator
		/// </summary>
		/// <param name="probability">Probability that disaster will occure (real value from range [0, 1])</param>
		/// <param name="percentage">Fraction of population to kill (real value from range [0, 1])</param>
		public DisasterOperator(double probability, double fraction)
		{
			if (probability > 1.0 || probability < 0.0)
				throw new Exception("Disaster probability must be a real number from range [0, 1]");
			if (fraction > 1.0 || fraction < 0.0)
				throw new Exception("Disaster fraction must be a real number from range [0, 1]");
			this.probability = probability;
			this.fraction = fraction;
		}

		/// <summary>
		/// Execute operator
		/// </summary>
		/// <param name="population">population</param>
		/// <returns>new population</returns>
		public Population<T> Execute(Population<T> population)
		{
			if (random.NextDouble() > this.probability)
				return population;
			int quantity = (int)(population.Size * this.fraction);
			int chromosomeLength = population[0].ChromosomeLength;
			EvaluateChromosomeDelegate objectiveFunction = population[0].ObjectiveFunction;

			population.Individuals.Sort();
			for (int i = population.Size - 1, j = 0; j < quantity; j++, i--)
			{
				T ind = (T)Activator.CreateInstance(typeof(T));
				ind.ObjectiveFunction = objectiveFunction;
				ind.SetRandomChromosome(chromosomeLength);
				population[i] = ind;
			}
			return population;
		}

        public override string ToString()
        {
            return String.Format(System.Globalization.CultureInfo.InvariantCulture.NumberFormat,
                "DisasterOperator\n\tprobability {0}\n\tfraction {1}",
                probability, fraction);

        }
	}
}
